package chatclient_01;

import chatclient_01.dialogs.AboutDialog;
import chatclient_01.dialogs.ConnectDialog;
import chatclient_01.dialogs.CreditsDialog;
import chatclient_01.dialogs.HelpDialog;
import chatclient_01.dialogs.NameListDialog;
import chatclient_01.dialogs.OptionsDialog;
import chatclient_01.dialogs.StyleDialog;
import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.minlog.Log;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.LayoutStyle;
import javax.swing.ListModel;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyledDocument;
import network_01.Network;
import network_01.ResourceManager;

public class ChatClient extends JFrame {

  private static final long serialVersionUID = 1L;
  private Style currentStyle = Network.getDefaultStyle();
  private TrayManager trayManager;
  private boolean minimizeToTray = true;
  private StyledDocument msgDocument = null;
  private int nameFocusIndex = 0;
  private Client client = null;
  private String clientName = "Client";
  private String hostIP = "localhost";
  private ConnectDialog connectDialog = null;
  private StyleDialog styleDialog = null;
  private HelpDialog helpDialog = null;
  private AboutDialog aboutDialog = null;
  private CreditsDialog creditsDialog = null;
  private OptionsDialog optionsDialog = null;
  private NameListDialog nameListDialog = null;
  private ButtonTabComponent allTabComponent = null;
  private JMenuItem aboutMenuItem;
  private JMenuBar chatMenuBar;
  private JTabbedPane chatTabbedPane;
  private JTextPane chatTextPane;
  private JMenuItem connectMenuItem;
  private JMenuItem creditsMenuItem;
  private JMenu editMenu;
  private JMenuItem exitMenuItem;
  private MenuItem exitTrayMenuItem;
  private JMenu formatMenu;
  private JMenu helpMenu;
  private JMenuItem helpMenuItem;
  private MenuItem helpTrayMenuItem;
  private JPopupMenu jPopupMenu1;
  private JScrollPane jScrollPane1;
  private JPopupMenu.Separator jSeparator1;
  private JPopupMenu.Separator jSeparator2;
  private JSplitPane jSplitPane1;
  private JMenu msgMenu;
  private JTextField msgTextField;
  private JList nameList;
  private JScrollPane nameScrollPane;
  private MenuItem openTrayMenuItem;
  private JMenuItem optionsMenuItem;
  private JMenuItem pmMenuItem;
  private JMenuItem sendPMmenuItem;
  private JMenuItem sendToAllMenuItem;
  private JMenuItem styleMenuItem;
  private JMenu toolsMenu;
  private PopupMenu trayPopupMenu;
  private JMenu viewMenu;

  public ChatClient() {
    initComponents();
    initDialogs();
    initClient();
    this.msgDocument = this.chatTextPane.getStyledDocument();

    setTitle(this.clientName);
    setIconImage(ResourceManager.createImage(getClass(), "resources/eicon12_happy.png"));
    setVisible(true);
    this.allTabComponent = new ButtonTabComponent(this.chatTabbedPane, false);
    this.chatTabbedPane.setTabComponentAt(0, this.allTabComponent);
    this.chatTabbedPane.addChangeListener(new ChangeListener() {

      @Override
      public void stateChanged(ChangeEvent evt) {
        ChatClient.this.test(evt);
      }
    });
    if (SystemTray.isSupported()) {
      this.trayManager = new TrayManager("resources/19.gif", this.trayPopupMenu);
      this.trayManager.setImageAutoSize(true);
      this.trayManager.addActionListener(new ActionListener() {

        @Override
        protected Object clone() throws CloneNotSupportedException {
          return super.clone();
        }

        @Override
        public void actionPerformed(ActionEvent e) {
          ChatClient.this.trayIconActionPerformed(e);
        }
      });
    } else {
      Logger.getLogger(getName()).log(Level.SEVERE, "System Tray is not supported.");
      this.minimizeToTray = false;
    }
  }

  private void initDialogs() {
    this.connectDialog = new ConnectDialog(this, true);
    this.styleDialog = new StyleDialog(this, true);
    this.helpDialog = new HelpDialog(this, true);
    this.aboutDialog = new AboutDialog(this, true);
    this.creditsDialog = new CreditsDialog(this, true);
    this.optionsDialog = new OptionsDialog(this, true);
    this.nameListDialog = new NameListDialog(this, true);
  }

  private void initClient() {
    this.client = new Client();
    Network.register(this.client);
    this.client.addListener(new Listener() {

      @Override
      public void received(Connection connection, Object object) {
        if ((object instanceof Network.RecipientList)) {
          Network.RecipientList nameList = (Network.RecipientList) object;
          ChatClient.this.updateNames(nameList.names);
          return;
        }

        if ((object instanceof Network.ChatMessage)) {
          Network.ChatMessage chatMessage = (Network.ChatMessage) object;
          ChatClient.this.postMessage(chatMessage);
          return;
        }
      }

      @Override
      public void disconnected(Connection connection) {
        EventQueue.invokeLater(new Runnable() {

          @Override
          public void run() {
            ChatClient.this.connectMenuItem.setText("Connect...");
          }
        });
      }
    });
  }

  private void trayIconActionPerformed(ActionEvent evt) {
    setVisible(true);
    setState(0);
    toFront();
  }

  private void test(ChangeEvent evt) {
    ((ButtonTabComponent) this.chatTabbedPane.getTabComponentAt(this.chatTabbedPane.getSelectedIndex())).setBold(false);
  }

  private void initComponents() {
    this.trayPopupMenu = new PopupMenu();
    this.openTrayMenuItem = new MenuItem();
    this.helpTrayMenuItem = new MenuItem();
    this.exitTrayMenuItem = new MenuItem();
    this.jPopupMenu1 = new JPopupMenu();
    this.pmMenuItem = new JMenuItem();
    this.jSplitPane1 = new JSplitPane();
    this.nameScrollPane = new JScrollPane();
    this.nameList = new JList();
    this.chatTabbedPane = new JTabbedPane();
    this.jScrollPane1 = new JScrollPane();
    this.chatTextPane = new JTextPane();
    this.msgTextField = new JTextField();
    this.chatMenuBar = new JMenuBar();
    this.msgMenu = new JMenu();
    this.connectMenuItem = new JMenuItem();
    this.sendToAllMenuItem = new JMenuItem();
    this.sendPMmenuItem = new JMenuItem();
    this.jSeparator1 = new JPopupMenu.Separator();
    this.exitMenuItem = new JMenuItem();
    this.editMenu = new JMenu();
    this.viewMenu = new JMenu();
    this.formatMenu = new JMenu();
    this.styleMenuItem = new JMenuItem();
    this.toolsMenu = new JMenu();
    this.optionsMenuItem = new JMenuItem();
    this.helpMenu = new JMenu();
    this.helpMenuItem = new JMenuItem();
    this.jSeparator2 = new JPopupMenu.Separator();
    this.aboutMenuItem = new JMenuItem();
    this.creditsMenuItem = new JMenuItem();

    this.trayPopupMenu.setFont(new Font("Tahoma", 0, 11));
    this.trayPopupMenu.setLabel("popupMenu1");

    this.openTrayMenuItem.setFont(new Font("Tahoma", 1, 11));
    this.openTrayMenuItem.setLabel("Open");
    this.openTrayMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.openTrayMenuItemActionPerformed(evt);
      }
    });
    this.trayPopupMenu.add(this.openTrayMenuItem);

    this.helpTrayMenuItem.setFont(new Font("Tahoma", 0, 11));
    this.helpTrayMenuItem.setLabel("Help");
    this.helpTrayMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.helpTrayMenuItemActionPerformed(evt);
      }
    });
    this.trayPopupMenu.add(this.helpTrayMenuItem);
    this.trayPopupMenu.addSeparator();
    this.exitTrayMenuItem.setFont(new Font("Tahoma", 0, 11));
    this.exitTrayMenuItem.setLabel("Exit");
    this.exitTrayMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.exitTrayMenuItemActionPerformed(evt);
      }
    });
    this.trayPopupMenu.add(this.exitTrayMenuItem);

    this.pmMenuItem.setText("Send message");
    this.pmMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.pmMenuItemActionPerformed(evt);
      }
    });
    this.jPopupMenu1.add(this.pmMenuItem);

    setDefaultCloseOperation(2);
    setLocationByPlatform(true);
    addWindowListener(new WindowAdapter() {

      @Override
      public void windowClosed(WindowEvent evt) {
        ChatClient.this.formWindowClosed(evt);
      }

      @Override
      public void windowIconified(WindowEvent evt) {
        ChatClient.this.formWindowIconified(evt);
      }
    });
    this.jSplitPane1.setDividerLocation(121);

    this.nameList.setSelectionMode(0);
    this.nameList.setToolTipText("List of connections");
    this.nameList.setComponentPopupMenu(this.jPopupMenu1);
    this.nameList.addFocusListener(new FocusAdapter() {

      @Override
      public void focusGained(FocusEvent evt) {
        ChatClient.this.nameListFocusGained(evt);
      }

      @Override
      public void focusLost(FocusEvent evt) {
        ChatClient.this.nameListFocusLost(evt);
      }
    });
    this.nameScrollPane.setViewportView(this.nameList);

    this.jSplitPane1.setLeftComponent(this.nameScrollPane);

    this.chatTextPane.setEditable(false);
    this.chatTextPane.setFocusable(false);
    this.chatTextPane.setRequestFocusEnabled(false);
    this.jScrollPane1.setViewportView(this.chatTextPane);

    this.chatTabbedPane.addTab("  All  ", this.jScrollPane1);

    this.jSplitPane1.setRightComponent(this.chatTabbedPane);

    this.msgTextField.setToolTipText("You type here.");
    this.msgTextField.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.msgTextFieldActionPerformed(evt);
      }
    });
    this.msgMenu.setMnemonic('m');
    this.msgMenu.setText("Message");

    this.connectMenuItem.setText("Connect...");
    this.connectMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.connectMenuItemActionPerformed(evt);
      }
    });
    this.msgMenu.add(this.connectMenuItem);

    this.sendToAllMenuItem.setMnemonic('a');
    this.sendToAllMenuItem.setText("Send to All");
    this.sendToAllMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.sendToAllMenuItemActionPerformed(evt);
      }
    });
    this.msgMenu.add(this.sendToAllMenuItem);

    this.sendPMmenuItem.setText("Send PM...");
    this.sendPMmenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.sendPMmenuItemActionPerformed(evt);
      }
    });
    this.msgMenu.add(this.sendPMmenuItem);
    this.msgMenu.add(this.jSeparator1);

    this.exitMenuItem.setText("Exit");
    this.exitMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.exitMenuItemActionPerformed(evt);
      }
    });
    this.msgMenu.add(this.exitMenuItem);

    this.chatMenuBar.add(this.msgMenu);

    this.editMenu.setMnemonic('e');
    this.editMenu.setText("Edit");
    this.chatMenuBar.add(this.editMenu);

    this.viewMenu.setMnemonic('v');
    this.viewMenu.setText("View");
    this.chatMenuBar.add(this.viewMenu);

    this.formatMenu.setMnemonic('f');
    this.formatMenu.setText("Format");

    this.styleMenuItem.setMnemonic('s');
    this.styleMenuItem.setText("Style...");
    this.styleMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.styleMenuItemActionPerformed(evt);
      }
    });
    this.formatMenu.add(this.styleMenuItem);

    this.chatMenuBar.add(this.formatMenu);

    this.toolsMenu.setMnemonic('t');
    this.toolsMenu.setText("Tools");

    this.optionsMenuItem.setMnemonic('o');
    this.optionsMenuItem.setText("Options");
    this.optionsMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.optionsMenuItemActionPerformed(evt);
      }
    });
    this.toolsMenu.add(this.optionsMenuItem);

    this.chatMenuBar.add(this.toolsMenu);

    this.helpMenu.setMnemonic('h');
    this.helpMenu.setText("Help");

    this.helpMenuItem.setMnemonic('t');
    this.helpMenuItem.setText("Help Topic");
    this.helpMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.helpMenuItemActionPerformed(evt);
      }
    });
    this.helpMenu.add(this.helpMenuItem);
    this.helpMenu.add(this.jSeparator2);

    this.aboutMenuItem.setMnemonic('b');
    this.aboutMenuItem.setText("About");
    this.aboutMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.aboutMenuItemActionPerformed(evt);
      }
    });
    this.helpMenu.add(this.aboutMenuItem);

    this.creditsMenuItem.setMnemonic('c');
    this.creditsMenuItem.setText("Credits");
    this.creditsMenuItem.addActionListener(new ActionListener() {

      @Override
      public void actionPerformed(ActionEvent evt) {
        ChatClient.this.creditsMenuItemActionPerformed(evt);
      }
    });
    this.helpMenu.add(this.creditsMenuItem);

    this.chatMenuBar.add(this.helpMenu);

    setJMenuBar(this.chatMenuBar);

    GroupLayout layout = new GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING).addComponent(this.msgTextField, -1, 535, 32767).addComponent(this.jSplitPane1, -1, 535, 32767));

    layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING).addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup().addComponent(this.jSplitPane1, -1, 239, 32767).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(this.msgTextField, -2, 25, -2)));

    pack();
  }

  private void styleMenuItemActionPerformed(ActionEvent evt) {
    this.styleDialog.setVisible(true);
  }

  private void helpMenuItemActionPerformed(ActionEvent evt) {
    this.helpDialog.setVisible(true);
  }

  private void aboutMenuItemActionPerformed(ActionEvent evt) {
    this.aboutDialog.setVisible(true);
  }

  private void nameListFocusGained(FocusEvent evt) {
    this.nameList.setSelectedIndex(this.nameFocusIndex);
  }

  private void nameListFocusLost(FocusEvent evt) {
    int n = this.nameList.getSelectedIndex();
    if (n == -1) {
      this.nameFocusIndex = 0;
    } else {
      this.nameFocusIndex = n;
    }
  }

  private void creditsMenuItemActionPerformed(ActionEvent evt) {
    this.creditsDialog.setVisible(true);
  }

  private void exitMenuItemActionPerformed(ActionEvent evt) {
    dispose();
  }

  private void optionsMenuItemActionPerformed(ActionEvent evt) {
    this.optionsDialog.setVisible(true);
  }

  private void formWindowIconified(WindowEvent evt) {
    if (this.minimizeToTray) {
      setVisible(false);
      this.trayManager.addIcon();
    }
  }

  private void exitTrayMenuItemActionPerformed(ActionEvent evt) {
    dispose();
  }

  private void openTrayMenuItemActionPerformed(ActionEvent evt) {
    setVisible(true);
    setState(0);
    toFront();
    this.trayManager.removeIcon();
  }

  private void helpTrayMenuItemActionPerformed(ActionEvent evt) {
    this.helpDialog.setVisible(true);
  }

  private void sendToAllMenuItemActionPerformed(ActionEvent evt) {
    this.msgTextField.requestFocus();
    this.chatTabbedPane.setSelectedIndex(0);
  }

  private void pmMenuItemActionPerformed(ActionEvent evt) {
    int index = this.nameList.getSelectedIndex();
    if (index == -1) {
      return;
    }
    setSelectedName(index);
  }

  private void msgTextFieldActionPerformed(ActionEvent evt) {
    if (this.msgTextField.getText().length() == 0) {
      return;
    }
    this.client.sendTCP(getMessage());
    this.msgTextField.setText("");
    this.msgTextField.requestFocus();
  }

  private void formWindowClosed(WindowEvent evt) {
    this.client.stop();
    this.trayManager.removeIcon();
  }

  private void connectMenuItemActionPerformed(ActionEvent evt) {
    if (this.client.isConnected()) {
      this.client.stop();
    } else {
      this.connectDialog.setVisible(true);
    }
  }

  private void sendPMmenuItemActionPerformed(ActionEvent evt) {
    this.nameListDialog.setVisible(true);
  }

  private Network.ChatMessage getMessage() {
    Network.ChatMessage cm = new Network.ChatMessage();
    cm.text = this.msgTextField.getText().trim();
    cm.style = this.currentStyle;
    cm.recipient = this.chatTabbedPane.getTitleAt(this.chatTabbedPane.getSelectedIndex());
    cm.origin = this.clientName;
    return cm;
  }

  private void updateNames(final String[] names) {
    EventQueue.invokeLater(new Runnable() {

      @Override
      public void run() {
        DefaultListModel nameListModel = new DefaultListModel();
        for (String name : names) {
          if (!name.equals(ChatClient.this.clientName)) {
            nameListModel.addElement(name);
          }
        }
        ChatClient.this.nameList.setModel(nameListModel);
        ChatClient.this.nameList.setSelectedIndex(ChatClient.this.nameFocusIndex);
      }
    });
  }

  public void postMessage(final Network.ChatMessage message) {
    EventQueue.invokeLater(new Runnable() {

      @Override
      public void run() {
        try {
          if (message.recipient.equals("  All  ")) {
            ChatClient.this.msgDocument.insertString(ChatClient.this.msgDocument.getLength(), message.text + "\n", message.style);
            if (ChatClient.this.chatTabbedPane.getSelectedIndex() != 0) {
              ChatClient.this.allTabComponent.setBold(true);
            }
          } else {
            boolean found = false;

            int n = ChatClient.this.chatTabbedPane.getTabCount();
            for (int i = 0; i < n; i++) {
              if ((ChatClient.this.chatTabbedPane.getTitleAt(i).equals(message.origin)) || (ChatClient.this.chatTabbedPane.getTitleAt(i).equals(message.recipient))) {
                StyledDocument sd = ((MessagePane) ChatClient.this.chatTabbedPane.getComponentAt(i)).getDocument();
                sd.insertString(sd.getLength(), message.text + "\n", message.style);
                if (ChatClient.this.chatTabbedPane.getSelectedIndex() != i) {
                  ((ButtonTabComponent) ChatClient.this.chatTabbedPane.getTabComponentAt(i)).setBold(true);
                }
                found = true;
                break;
              }
            }

            if ((!found) && (!message.origin.equals(ChatClient.this.clientName))) {
              ChatClient.this.chatTabbedPane.addTab(message.origin, new MessagePane());
              ChatClient.this.chatTabbedPane.setTabComponentAt(ChatClient.this.chatTabbedPane.getTabCount() - 1, new ButtonTabComponent(ChatClient.this.chatTabbedPane, true));
              StyledDocument sd = ((MessagePane) ChatClient.this.chatTabbedPane.getComponentAt(ChatClient.this.chatTabbedPane.getTabCount() - 1)).getDocument();
              sd.insertString(sd.getLength(), message.text + "\n", message.style);
              if (ChatClient.this.chatTabbedPane.getSelectedIndex() != ChatClient.this.chatTabbedPane.getTabCount() - 1) {
                ((ButtonTabComponent) ChatClient.this.chatTabbedPane.getTabComponentAt(ChatClient.this.chatTabbedPane.getTabCount() - 1)).setBold(true);
              }
            }
          }
        } catch (BadLocationException ex) {
          Logger.getLogger(ChatClient.class.getName()).log(Level.SEVERE, null, ex);
        }
      }
    });
    if (getState() == 1) {
      this.trayManager.displayMessage("Messssssage!", "Naai message dodong!", TrayIcon.MessageType.INFO);
    }
  }

  public void connectToHost(String host, String name) {
    this.hostIP = host;
    this.clientName = name;
    this.client.start();
    EventQueue.invokeLater(new Runnable() {

      @Override
      public void run() {
        try {
          ChatClient.this.client.connect(5000, ChatClient.this.hostIP, 54555);
        } catch (IOException ex) {
          Log.error(null, ex);
          System.exit(1);
        }

        Network.RegisterName registerName = new Network.RegisterName();
        registerName.name = ChatClient.this.clientName;
        ChatClient.this.setTitle(ChatClient.this.clientName);
        ChatClient.this.client.sendTCP(registerName);
        ChatClient.this.connectMenuItem.setText("Disconnect");
      }
    });
  }

  public ListModel getNameListModel() {
    return this.nameList.getModel();
  }

  public void setSelectedName(int index) {
    this.nameList.setSelectedIndex(index);
    String name = (String) this.nameList.getModel().getElementAt(index);
    int n = this.chatTabbedPane.getTabCount();
    boolean found = false;
    for (int i = 1; i < n; i++) {
      if (this.chatTabbedPane.getTitleAt(i).equals(name)) {
        this.chatTabbedPane.setSelectedIndex(i);
        found = true;
      }
    }
    if (!found) {
      this.chatTabbedPane.addTab(name, new MessagePane());
      this.chatTabbedPane.setTabComponentAt(n, new ButtonTabComponent(this.chatTabbedPane, true));
      this.chatTabbedPane.setSelectedIndex(n);
    }
    this.msgTextField.requestFocus();
  }

  public Style getCurrentStyle() {
    return this.currentStyle;
  }

  public void styleChangeCommit(Style s) {
    this.currentStyle = s;
  }

  public void setMinimizeToTray(boolean b) {
    this.minimizeToTray = b;
  }

  public boolean isMinimizeToTray() {
    return this.minimizeToTray;
  }

  public static void main(String[] args) {
    Log.set(2);
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (Exception e) {
      Log.error(null, e);
    }

    EventQueue.invokeLater(new Runnable() {

      @Override
      public void run() {
        new ChatClient();
      }
    });
  }
}